package kernel_gui.gui.extended;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.util.List;

import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;

import kernel_gui.gui.generic.graphic.ControlCountries;

import common.entities.enums.ACTION;
import common.entities.persistent.Country;

public class EControlCountries extends ControlCountries{

	/**
	 * 
	 */
	private static final long serialVersionUID = -6027773074188209999L;
	
	
	private String countrySubStr = null;
	
	private int count = 0;
	private int numberOfRecordsPerPage;
	private int currentPage = 0;
	private int totalPages = 0;
	
	private List<Country> currentDataInTableModel;
	private DefaultTableModel currentTableModel = new DefaultTableModel();
	
	private int currentRowBeingUpdated = -1;
	private int currentNewRow = -1;
	
	
	/*General*/
	
	public EControlCountries() {
		
		/*Command to execute on cancel*/
		setExecuteOnCancel(new CommandToExecute() {
			
			@Override
			public void command(Object answer) {
				Component components[] = MainPanel.getComponents();
				for (Component c : components) {
					if(c instanceof JPanel){
						JPanel panel = (JPanel) c;
						Component pcomponents[] = panel.getComponents();
						for(Component pc : pcomponents){
							if(pc instanceof JPanel){
								JPanel anotherPanel = (JPanel) pc;
								Component pccomponents[] = anotherPanel.getComponents();
								for(Component pcc : pccomponents){
									pcc.setEnabled(true);
								}
							}
							pc.setEnabled(true);
						}
					}
					
					c.setEnabled(true);
				}
				ResultTable.setEnabled(true);
				updateButtonsAndLabelsAfterReturnedResultSet();
				setWindowComponentsWhenCalledFromAnotherFrame();
			}
		});
		
		/*Command to execute before long request*/
		setExecuteBeforeLongRequest(new CommandToExecute() {
			
			@Override
			public void command(Object answer) {
				Component components[] = MainPanel.getComponents();
				for (Component c : components) {
					if(c instanceof JPanel){
						JPanel panel = (JPanel) c;
						Component pcomponents[] = panel.getComponents();
						for(Component pc : pcomponents){
							if(pc instanceof JPanel){
								JPanel anotherPanel = (JPanel) pc;
								Component pccomponents[] = anotherPanel.getComponents();
								for(Component pcc : pccomponents){
									pcc.setEnabled(false);
								}
							}
							pc.setEnabled(false);
						}
					}
					
					c.setEnabled(false);
				}
				ResultTable.setEnabled(false);
			}
		});
		
		/*Update the numberOfRecords variable*/
		NumOfRecordsInPageComboBox.setSelectedIndex(2);
		numberOfRecordsPerPage = Integer.parseInt(NumOfRecordsInPageComboBox.getSelectedItem().toString());
		
		/*Create defaultive model*/
		currentTableModel = new DefaultTableModel(new Object [][] {},new String [] {"Country Name"});
		ResultTable.setModel(currentTableModel);
		updateButtonsAndLabelsAfterReturnedResultSet();
			
	}
	/*Search Panel*/
	@Override
	protected void SearchButtonActionPerformed(ActionEvent evt) {
		if(unsavedChangesCheck(3)){
			if(getSearchVariablesData()){
				countResultAndPopulateTable(1);
			}
		}

	}
	
	private boolean getSearchVariablesData(){
		
		if(!PartOfCountryNameTextField.getText().equals(""))
			countrySubStr = PartOfCountryNameTextField.getText();
		else
			countrySubStr = null;
		
		
		return true;
	}
	
	protected void countResultAndPopulateTable(int page){
		
		final int pageWhenFinished = page;
		/*Command to execute after returning from*/
		int requestID = executeBeforeLongRequest(new CommandToExecute() {
			
			@Override
			public void command(Object answer) {
				/*Updated count & labels*/
				EControlCountries.this.count = Integer.parseInt(answer.toString());
				EControlCountries.this.FoundNumberLabel.setText(numbers_nf.format(EControlCountries.this.count));
				
				if(EControlCountries.this.count != 0)
					EControlCountries.this.currentPage = 1;
				else
					EControlCountries.this.currentPage = 0;
				
				EControlCountries.this.PageNumberLabel.setText(numbers_nf.format(EControlCountries.this.currentPage));
				EControlCountries.this.totalPages = (int) Math.ceil(((float)EControlCountries.this.count)/numberOfRecordsPerPage);
				EControlCountries.this.TotalPageNumberLabel.setText(numbers_nf.format(EControlCountries.this.totalPages));
									
				/*Get the data*/
				populateTableWithResults(pageWhenFinished);
				
			}
		});
	
		
		kernel.countCountries(countrySubStr,null, requestID);
	}
	
	private void populateTableWithResults(int page){
		/*Command to execute after returning from*/
		
		final int pageNumberToSet = page;
		int requestID = executeBeforeLongRequest(new CommandToExecute() {
			
			@SuppressWarnings("unchecked")
			@Override
			public void command(Object answer) {
				if(answer != null){
					EControlCountries.this.currentDataInTableModel = (List<Country>) answer;
					
					/*Create new table model, and insert the rows*/
					currentTableModel = new DefaultTableModel(new Object [][] {},
							new String [] {"Country Name"});
					/*Add the tableModelListener for handeling table changes (update, insert)*/
					currentTableModel.addTableModelListener(new TableModelListener() {
						
						@Override
						public void tableChanged(TableModelEvent e) {
							tableChangedEventHandler(e);
						}
					});
					
					/*Add the result data to the table model*/
					for(int i = 0; i < EControlCountries.this.currentDataInTableModel.size(); i++){
						Country country = EControlCountries.this.currentDataInTableModel.get(i);
						Object[] rowData = new Object[] {country.getName()};
						currentTableModel.insertRow(i, rowData);
					}
					
					
					/*Set the table model and the first page of it*/
					ResultTable.setModel(currentTableModel);
					if(EControlCountries.this.count != 0)
						currentPage = pageNumberToSet;
					else
						currentPage = 0;
					
					updateButtonsAndLabelsAfterReturnedResultSet();
				}
			}
		});
		
		int from = (page <= 0) ? 0 : (page-1)*numberOfRecordsPerPage;
		int to = (page <= 0) ? 0 : page*numberOfRecordsPerPage;
		
		kernel.getCountries(countrySubStr, from, to, requestID);
	}
	
	
	/*Table Panel*/
	
	private void updateButtonsAndLabelsAfterReturnedResultSet(){
		EControlCountries.this.PageNumberLabel.setText(String.valueOf(EControlCountries.this.currentPage));
		EControlCountries.this.totalPages = (int) Math.ceil(((float)EControlCountries.this.count)/numberOfRecordsPerPage);
		EControlCountries.this.TotalPageNumberLabel.setText(String.valueOf(EControlCountries.this.totalPages));
		
		if(totalPages == 0){
			NextButton.setEnabled(false);
			PreviousButton.setEnabled(false);
			NumOfRecordsInPageComboBox.setEnabled(false);
		}else{
			NextButton.setEnabled(true);
			PreviousButton.setEnabled(true);
			NumOfRecordsInPageComboBox.setEnabled(true);
		}
					
	}

	@Override
	protected void NumOfRecordsInPageComboBoxActionPerformed(ActionEvent evt) {
		if(unsavedChangesCheck(3)){
			numberOfRecordsPerPage = Integer.parseInt(NumOfRecordsInPageComboBox.getSelectedItem().toString());
			
			/*fix problem when the user is on page 100 in 5rec-per-page but there is no page 100 in 100rec-per-page*/
			int expectedTotalPages = (int) Math.ceil(((float)EControlCountries.this.count)/numberOfRecordsPerPage);
	
			
			if(currentPage > expectedTotalPages)
				currentPage = expectedTotalPages;
			
			populateTableWithResults(currentPage);
		}

	}
	
	@Override
	protected void PreviousButtonActionPerformed(ActionEvent evt) {
		if(unsavedChangesCheck(3)){
			if(currentPage > 1){
				int askingPage = currentPage-1;
				populateTableWithResults(askingPage);
			}else{
				populateTableWithResults(totalPages);
			}
		}

	}
	
	@Override
	protected void NextButtonActionPerformed(ActionEvent evt) {
		if(unsavedChangesCheck(3)){
			if(currentPage < totalPages){
				int askingPage = currentPage+1;
				populateTableWithResults(askingPage);
			}else{
				populateTableWithResults(1);
			}
		}

	}
	
	protected void tableChangedEventHandler(TableModelEvent e){
		if(!isCalledAsLongRequestFromOtherFrame()){
			if(e.getType() == TableModelEvent.UPDATE){/*If this is update*/
				int rownum = e.getFirstRow();
				if(rownum != currentNewRow){
					/*if the row we are changing isn't the currentNewRow*/
					if(currentNewRow != -1){
						/*if we started insert - don't allow it*/
						int userAnswer = JOptionPane.showConfirmDialog(this, "You cannot update while in insert.\n" +
								"Do you wish to commit your previous change?\n" +
								"(pressing no will discard your change)", "", JOptionPane.YES_NO_OPTION);
						switch(userAnswer){
							case JOptionPane.YES_OPTION:
								/*discard current change*/
								undoChangesToRow(rownum);
								/*Updating previous changes*/
								insertNewRecordIntoDB();
								break;
							case JOptionPane.NO_OPTION:
								/*Discarding previous changes*/
								currentTableModel.removeRow(EControlCountries.this.currentNewRow);
								InsertButton.setForeground(DeleteButton.getForeground());
								UpdateButton.setForeground(Color.red);
								currentNewRow = -1;
								currentRowBeingUpdated = rownum;
						}
					}else{/*we havent started insert*/
						if(currentRowBeingUpdated == -1){
							currentRowBeingUpdated = rownum;
							UpdateButton.setForeground(Color.red);
						}else if(currentRowBeingUpdated != rownum){
							int userAnswer = JOptionPane.showConfirmDialog(this, "You can only update one row at a time.\n" +
									"Do you wish to commit your previous change?\n" +
									"(pressing no will discard your change)", "", JOptionPane.YES_NO_OPTION);
							switch(userAnswer){
								case JOptionPane.YES_OPTION:
									/*discard current change*/
									undoChangesToRow(rownum);
									/*Updating previous changes*/
									updateChangesInTable();
									break;
								case JOptionPane.NO_OPTION:
									/*Discarding previous changes*/
									undoChangesToRow(currentRowBeingUpdated);
									UpdateButton.setForeground(Color.red);
									currentRowBeingUpdated = rownum;
							}
						}
					}
				
				}	
			}	
		}
	}
	
	private void undoChangesToRow(int rowNum){
		currentTableModel.removeRow(rowNum);
		Country country = currentDataInTableModel.get(rowNum);
		currentTableModel.insertRow(rowNum, new Object[] {country.getName()});
	}
	
	
	/*Action Panel*/
	
	/*Action Panel*/
	/**
	 * 
	 * @return true if there aren't any unsaved changed, otherwise false
	 */
	private boolean unsavedChangesCheck(int create_update_all){
		if(currentRowBeingUpdated != -1 && create_update_all != 2){
			int userAnswer = JOptionPane.showConfirmDialog(this, "You have unsaved change.\n" +
					"Do you wish to update the record?\n" +
					"(pressing no will discard your change)", "", JOptionPane.YES_NO_OPTION);
			switch(userAnswer){
				case JOptionPane.YES_OPTION:
					/*Updating change*/
					updateChangesInTable();
					return false;
				case JOptionPane.NO_OPTION:
					/*Discarding change*/
					undoChangesToRow(currentRowBeingUpdated);
					UpdateButton.setForeground(DeleteButton.getForeground());
					currentRowBeingUpdated = -1;
					return true;
			}
		}else if(currentNewRow != -1 && create_update_all != 1){
			int userAnswer = JOptionPane.showConfirmDialog(this, "You have unsaved change.\n" +
					"Do you wish to insert the record?\n" +
					"(pressing no will discard your record)", "", JOptionPane.YES_NO_OPTION);
			switch(userAnswer){
				case JOptionPane.YES_OPTION:
					/*Updating change*/
					insertNewRecordIntoDB();
					return false;
				case JOptionPane.NO_OPTION:
					/*Discarding change*/
					currentTableModel.removeRow(EControlCountries.this.currentNewRow);
					InsertButton.setForeground(DeleteButton.getForeground());
					currentNewRow = -1;
					return true;
		}
		}
		
		return true;
	}
	
	@Override
	protected void DeleteButtonActionPerformed(ActionEvent evt) {
		if(unsavedChangesCheck(3)){
			int[] selectedRowIndexes = ResultTable.getSelectedRows();
			if(selectedRowIndexes.length != 1){
				JOptionPane.showMessageDialog(this, "Please select ONE record to delete");
			}else{
				/*Command to execute after returning from*/
				int requestID = executeBeforeLongRequest(new CommandToExecute() {
					
					@Override
					public void command(Object answer) {
						//TODO - check if this is always right
						if(currentDataInTableModel.size() != 1)
							EControlCountries.this.countResultAndPopulateTable(currentPage);
						else
							EControlCountries.this.countResultAndPopulateTable(--currentPage);
					}
				});
				
				Country country = this.currentDataInTableModel.get(ResultTable.convertRowIndexToModel(selectedRowIndexes[0]));
				kernel.actionCountry(ACTION.DELETE, country, requestID);
			}
		}
	}
	
	@Override
	protected void UpdateButtonActionPerformed(ActionEvent evt) {
		if(currentRowBeingUpdated == -1){
			JOptionPane.showMessageDialog(this, "There are no changes to commit.");
		}else{
			updateChangesInTable();
		}

	}
	
	@Override
	protected void InsertButtonActionPerformed(ActionEvent evt) {
		if(currentRowBeingUpdated != -1){
			int userAnswer = JOptionPane.showConfirmDialog(this, "You cannot insert while in update.\n" +
					"Do you wish to commit your previous change?\n" +
					"(pressing no will discard your change)", "", JOptionPane.YES_NO_OPTION);
			switch(userAnswer){
				case JOptionPane.YES_OPTION:
					/*discard current change by not creating a new row*/
					/*Updating previous changes*/
					updateChangesInTable();
					return;
				case JOptionPane.NO_OPTION:
					/*Discarding previous changes*/
					undoChangesToRow(currentRowBeingUpdated);
					UpdateButton.setForeground(DeleteButton.getForeground());
					currentRowBeingUpdated = -1;
					break;
			}
		}
		if(unsavedChangesCheck(1)){/*pass insert mode*/
			if(currentNewRow == -1){
				InsertButton.setForeground(Color.red);
				currentTableModel.addRow(new Object[]{""});
				currentNewRow = currentTableModel.getRowCount()-1;
				ResultTable.changeSelection(currentNewRow, 1, false, false);
			}else{
				insertNewRecordIntoDB();
			}
		}


	}
	
	private Country parseDataFromTable(Country countryToUpdate, int rowNum){
		//TODO - this change selection doesn't help so much..(for some reason the selected jumps..)
		ResultTable.changeSelection(rowNum, 1, false, false);
		
		String newCountryName = currentTableModel.getValueAt(rowNum, 0).toString();
		
		
		return new Country(countryToUpdate.getId(),  newCountryName);
	}
	
	private void updateChangesInTable(){
		if(unsavedChangesCheck(2)){/*pass update mode*/
			/*Parse changes*/
			//TODO - this change selection doesn't help so much..(for some reason the selected jumps..)
			ResultTable.changeSelection(currentRowBeingUpdated, 1, false, false);
			
			
			final Country updatedCountry = parseDataFromTable(currentDataInTableModel.get(currentRowBeingUpdated),
					currentRowBeingUpdated);
			if(updatedCountry != null){/*If the parsing succeeded*/
				/*Command to execute after returning from*/
				int requestID = executeBeforeLongRequest(new CommandToExecute() {
					
					@Override
					public void command(Object answer) {
						EControlCountries.this.currentDataInTableModel.remove(EControlCountries.this.currentRowBeingUpdated);
						EControlCountries.this.currentDataInTableModel.add(EControlCountries.this.currentRowBeingUpdated, updatedCountry);
						UpdateButton.setForeground(DeleteButton.getForeground());
						EControlCountries.this.currentRowBeingUpdated = -1;
					}
				});
				
				
				kernel.actionCountry(ACTION.UPDATE, updatedCountry, requestID);
			}
		}
	}
	
	private void insertNewRecordIntoDB(){
		final Country newCountry= parseDataFromTable(new Country(),
				currentNewRow);
		
		if(newCountry != null){/*If the parsing succeeded*/
			/*Command to execute after returning from*/
			int requestID = executeBeforeLongRequest(new CommandToExecute() {
				
				@Override
				public void command(Object answer) {
					currentTableModel.removeRow(EControlCountries.this.currentNewRow);
					EControlCountries.this.currentNewRow = -1;
					InsertButton.setForeground(DeleteButton.getForeground());
					if(EControlCountries.this.currentPage != 0){/*If we are not inserting new records into empty set*/
						countResultAndPopulateTable(EControlCountries.this.currentPage);
					}
					
				}
			});
			
			
			kernel.actionCountry(ACTION.CREATE, newCountry, requestID);
		}
	}
	
	/*Going back*/

	@Override
	protected void BackButtonActionPerformed(ActionEvent evt) {
		if(unsavedChangesCheck(3)){
			//TODO - check if right..
			if(isCalledAsLongRequestFromOtherFrame()){
				int selectedRowIndx = ResultTable.getSelectedRow();
				if(selectedRowIndx != -1 && currentDataInTableModel != null){
					Country countryAnswer = currentDataInTableModel.get(ResultTable.convertRowIndexToModel(selectedRowIndx));
					setAnswerToCallingFrame(countryAnswer);
				}
				returnToCallingFrame();
			}else{
				openAnotherFrame(EControlPanelMenuFrame.class, true);
			}
		}
		
	}
	@Override
	protected void setWindowComponentsWhenCalledFromAnotherFrame() {
		if(isCalledAsLongRequestFromOtherFrame()){
			DeleteButton.setEnabled(false);
			UpdateButton.setEnabled(false);
			InsertButton.setEnabled(false);
			BackButton.setText("SELECT");
		}
		
	}


}
